#include "lcd.h"
#include "driver/spi_master.h"
#include "main.h"
#include "spi.h"
#include "driver/gpio.h"
#include "string.h"
#include "lvgl.h"
#include "soc/io_mux_reg.h"
#include "soc/spi_reg.h"

#define SWAPBYTES(i) ((i>>8) | (i<<8))

spi_device_handle_t lcd_spi;
//SPI传输之前会被调用
void lcd_spi_transfer_callback(spi_transaction_t *t)
{
    // lcd_dc_t *dc = (lcd_dc_t *) t->user;
    // gpio_set_level((int)dc->dc_io, (int)dc->dc_level);
    //LCD_CS_Clr();
}

static SemaphoreHandle_t _spi_mux = NULL;
uint8_t LCD_init(void)
{
    esp_err_t ret;

	_spi_mux = xSemaphoreCreateRecursiveMutex();

    spi_device_interface_config_t devcfg={
        .clock_speed_hz=60*1000*1000,           //Clock out at 26 MHz
        .mode=0,                                //SPI mode 0
        .spics_io_num=LCD_CS,               //CS pin
        .queue_size=7,                          //We want to be able to queue 7 transactions at a time
        .pre_cb=lcd_spi_transfer_callback,  //Specify pre-transfer callback to handle D/C line
    };
    ret=spi_bus_add_device(SPI_MODE, &devcfg, &lcd_spi);
    if(ret!=ESP_OK)
    {
        SPI_DEBUG("LCD SPI注册失败\r\n");
    }else
    {
        SPI_DEBUG("LCD SPI注册成功\r\n");

    }
#if LCD_IO_DC	
    gpio_pad_select_gpio(LCD_CS);
    gpio_pad_select_gpio(LCD_DC);
	gpio_pad_select_gpio(LCD_BK);

    gpio_set_direction(LCD_CS, GPIO_MODE_OUTPUT);
    gpio_set_direction(LCD_DC, GPIO_MODE_OUTPUT);
    gpio_set_direction(LCD_BK, GPIO_MODE_OUTPUT);

    LCD_BLK_Set();
#endif

	// uint16_t data=0x80f0;
	// while (1) 
	// {
	// 	//printf("runing...\r\n");
	// 	LCD_WR_dataa(0xf0,1);
	// 	//LCD_WR_REG(0x55); //Sleep out 

	// 	// SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(LCD_SPI_NUM), SPI_USR_MOSI_DBITLEN, 15, SPI_USR_MOSI_DBITLEN_S);
	// 	// WRITE_PERI_REG((SPI_W0_REG(LCD_SPI_NUM)), data);
	// 	// SET_PERI_REG_MASK(SPI_CMD_REG(LCD_SPI_NUM), SPI_USR);
	// 	// while (READ_PERI_REG(SPI_CMD_REG(LCD_SPI_NUM)) & SPI_USR);

	// 	vTaskDelay(1 / portTICK_PERIOD_MS); 
	// } 



    LCD_WR_REG(0x11); //Sleep out 
	LCD_WR_REG(0x36);
	if(USE_HORIZONTAL==0)
		LCD_WR_DATA8(0x00);
	else 
	if(USE_HORIZONTAL==1)
		LCD_WR_DATA8(0xC0);
	else 
	if(USE_HORIZONTAL==2)
		LCD_WR_DATA8(0x70);
	else 
		LCD_WR_DATA8(0xA0);

	LCD_WR_REG(0x3A); 
	LCD_WR_DATA8(0x05);

	LCD_WR_REG(0xB2);
	LCD_WR_DATA8(0x0C);
	LCD_WR_DATA8(0x0C);
	LCD_WR_DATA8(0x00);
	LCD_WR_DATA8(0x33);
	LCD_WR_DATA8(0x33); 

	LCD_WR_REG(0xB7); 
	LCD_WR_DATA8(0x35);  

	LCD_WR_REG(0xBB);
	LCD_WR_DATA8(0x19);

	LCD_WR_REG(0xC0);
	LCD_WR_DATA8(0x2C);

	LCD_WR_REG(0xC2);
	LCD_WR_DATA8(0x01);

	LCD_WR_REG(0xC3);
	LCD_WR_DATA8(0x12);   

	LCD_WR_REG(0xC4);
	LCD_WR_DATA8(0x20);  

	LCD_WR_REG(0xC6); 
	LCD_WR_DATA8(0x0F);    

	LCD_WR_REG(0xD0); 
	LCD_WR_DATA8(0xA4);
	LCD_WR_DATA8(0xA1);

	LCD_WR_REG(0xE0);
	LCD_WR_DATA8(0xD0);
	LCD_WR_DATA8(0x04);
	LCD_WR_DATA8(0x0D);
	LCD_WR_DATA8(0x11);
	LCD_WR_DATA8(0x13);
	LCD_WR_DATA8(0x2B);
	LCD_WR_DATA8(0x3F);
	LCD_WR_DATA8(0x54);
	LCD_WR_DATA8(0x4C);
	LCD_WR_DATA8(0x18);
	LCD_WR_DATA8(0x0D);
	LCD_WR_DATA8(0x0B);
	LCD_WR_DATA8(0x1F);
	LCD_WR_DATA8(0x23);

	LCD_WR_REG(0xE1);
	LCD_WR_DATA8(0xD0);
	LCD_WR_DATA8(0x04);
	LCD_WR_DATA8(0x0C);
	LCD_WR_DATA8(0x11);
	LCD_WR_DATA8(0x13);
	LCD_WR_DATA8(0x2C);
	LCD_WR_DATA8(0x3F);
	LCD_WR_DATA8(0x44);
	LCD_WR_DATA8(0x51);
	LCD_WR_DATA8(0x2F);
	LCD_WR_DATA8(0x1F);
	LCD_WR_DATA8(0x1F);
	LCD_WR_DATA8(0x20);
	LCD_WR_DATA8(0x23);
	LCD_WR_REG(0x21); 

	LCD_WR_REG(0x29); 


	while(1)
	{

		LCD_Fill_Colors2(0,0,LCD_W,LCD_H,GREEN);

		LCD_Fill_Colors2(0,0,LCD_W,LCD_H,BLUE);

	}



 	return 0;
}

/******************************************************************************
      函数说明：LCD串行数据写入函数
      入口数据：dat  要写入的串行数据
      返回值：  无
******************************************************************************/
void LCD_Writ_Bus(u8 dat) 
{	
    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));       //Zero out the transaction

    t.length=8;                     //Command is 8 bits
    t.tx_buffer=&dat;               //The data is the cmd itself
    t.user=(void*)0;                //D/C needs to be set to 0

    ret=spi_device_transmit(lcd_spi, &t);  //Transmit!
    if(ret!=ESP_OK)
    {
        SPI_DEBUG("LCD 通信失败\r\n");
    }else
    {
        //SPI_DEBUG("LCD 通信成功\r\n");

    }


}

void LCD_WR_dataa(u8 dat,u8 cmd)
{
	 //LCD_Writ_Bus(dat);
xSemaphoreTakeRecursive(_spi_mux, portMAX_DELAY);

	uint16_t vol=0;
	uint8_t temp=0;
    esp_err_t ret;
    spi_transaction_t t;

    memset(&t, 0, sizeof(t));       //Zero out the transaction

	//cmd=1;
	if(cmd==0)
	{
		vol=0x0080;
	}else
	{
		vol=0x0000;
	}
	//SPI_DEBUG("1:0x%x\r\n",vol);
	//dat=0xf3;
	vol|=(dat>>1);
	//SPI_DEBUG("2:0x%x\r\n",vol);
	vol|=((dat&0x01)<<15);

	//SPI_DEBUG("3:0x%x\r\n",vol);
	//vol=0x01f0;
	
    t.length=9;                     //Command is 8 bits
    t.tx_buffer=&vol;               //The data is the cmd itself
    t.user=(void*)0;                //D/C needs to be set to 0

    ret=spi_device_transmit(lcd_spi, &t);  //Transmit!
    if(ret!=ESP_OK)
    {
        SPI_DEBUG("LCD 通信失败\r\n");
    }else
    {
        //SPI_DEBUG("LCD 通信成功:0x%x\r\n",vol);

    }

	xSemaphoreGiveRecursive(_spi_mux);

}


void LCD_WR_dataaa(u8 dat,u8 cmd)
{
	 //LCD_Writ_Bus(dat);

xSemaphoreTakeRecursive(_spi_mux, portMAX_DELAY);

	uint16_t vol=0;
	uint8_t temp=0;

	if(cmd==0)
	{
		vol=0x0080;
	}else
	{
		vol=0x0000;
	}

	vol|=(dat>>1);
	vol|=((dat&0x01)<<15);

	SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(LCD_SPI_NUM), SPI_USR_MOSI_DBITLEN, 8, SPI_USR_MOSI_DBITLEN_S);
	WRITE_PERI_REG((SPI_W0_REG(LCD_SPI_NUM)), vol);
	SET_PERI_REG_MASK(SPI_CMD_REG(LCD_SPI_NUM), SPI_USR);
	while (READ_PERI_REG(SPI_CMD_REG(LCD_SPI_NUM)) & SPI_USR);

	xSemaphoreGiveRecursive(_spi_mux);
}



void LCD_WR_data_2byte(uint16_t dat)
{

xSemaphoreTakeRecursive(_spi_mux, portMAX_DELAY);

	uint32_t txdata=0;
	uint8_t buf[2];

	//0000 0000 0000 0000   0100 0000 1000 0000
	txdata|=1<<7|1<<14;

	txdata|=(buf[0]>>1);
	txdata|=(buf[0]&0x01)<<15;

	txdata|=((buf[1]|0x01)<<13);
	txdata|=(buf[1]&0x01)<<23;
	

	SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(LCD_SPI_NUM), SPI_USR_MOSI_DBITLEN, 2*9-1, SPI_USR_MOSI_DBITLEN_S);
	WRITE_PERI_REG((SPI_W0_REG(LCD_SPI_NUM)), txdata);
	SET_PERI_REG_MASK(SPI_CMD_REG(LCD_SPI_NUM), SPI_USR);
	while (READ_PERI_REG(SPI_CMD_REG(LCD_SPI_NUM)) & SPI_USR);

	xSemaphoreGiveRecursive(_spi_mux);

}


/******************************************************************************
      函数说明：LCD写入数据
      入口数据：dat 写入的数据
      返回值：  无
******************************************************************************/
void LCD_WR_DATA8(u8 dat)
{

#if LCD_IO_DC
	LCD_Writ_Bus(dat);

#else
	LCD_WR_dataa(dat,0);

#endif 
	 
	
   
}

/******************************************************************************
      函数说明：LCD写入数据
      入口数据：dat 写入的数据
      返回值：  无
******************************************************************************/
void LCD_WR_DATA(u16 dat)
{

#if LCD_IO_DC
	LCD_Writ_Bus(dat>>8);
	LCD_Writ_Bus(dat);

#else
	LCD_WR_dataa(dat>>8,0);
	LCD_WR_dataa(dat,0);
#endif


}


/******************************************************************************
      函数说明：LCD写入命令
      入口数据：dat 写入的命令
      返回值：  无
******************************************************************************/
void LCD_WR_REG(u8 dat)
{


#if LCD_IO_DC
	LCD_DC_Clr();//写命令
	LCD_Writ_Bus(dat);
	LCD_DC_Set();//写数据
#else
	LCD_WR_dataa(dat,1);	
#endif
	


}




/******************************************************************************
      函数说明：设置起始和结束地址
      入口数据：x1,x2 设置列的起始和结束地址
                y1,y2 设置行的起始和结束地址
      返回值：  无
******************************************************************************/
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
{
	if(USE_HORIZONTAL==0)
	{
		LCD_WR_REG(0x2a);//列地址设置
		LCD_WR_DATA(x1);
		LCD_WR_DATA(x2);
		LCD_WR_REG(0x2b);//行地址设置
		LCD_WR_DATA(y1);
		LCD_WR_DATA(y2);
		LCD_WR_REG(0x2c);//储存器写
	}
	else if(USE_HORIZONTAL==1)
	{
		LCD_WR_REG(0x2a);//列地址设置
		LCD_WR_DATA(x1);
		LCD_WR_DATA(x2);
		LCD_WR_REG(0x2b);//行地址设置
		LCD_WR_DATA(y1+80);
		LCD_WR_DATA(y2+80);
		LCD_WR_REG(0x2c);//储存器写
	}
	else if(USE_HORIZONTAL==2)
	{
		LCD_WR_REG(0x2a);//列地址设置
		LCD_WR_DATA(x1);
		LCD_WR_DATA(x2);
		LCD_WR_REG(0x2b);//行地址设置
		LCD_WR_DATA(y1);
		LCD_WR_DATA(y2);
		LCD_WR_REG(0x2c);//储存器写
	}
	else
	{
		LCD_WR_REG(0x2a);//列地址设置
		LCD_WR_DATA(x1+80);
		LCD_WR_DATA(x2+80);
		LCD_WR_REG(0x2b);//行地址设置
		LCD_WR_DATA(y1);
		LCD_WR_DATA(y2);
		LCD_WR_REG(0x2c);//储存器写
	}
}

/******************************************************************************
      函数说明：在指定位置画点
      入口数据：x,y 画点坐标
                color 点的颜色
      返回值：  无
******************************************************************************/
void LCD_DrawPoint(u16 x,u16 y,u16 color)
{
	LCD_Address_Set(x,y,x,y);//设置光标位置 
	LCD_WR_DATA(color);
} 


/******************************************************************************
      函数说明：在指定区域填充颜色
      入口数据：xsta,ysta   起始坐标
                xend,yend   终止坐标
								color       要填充的颜色
      返回值：  无
******************************************************************************/
void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color)
{          
	u16 i,j; 
	LCD_Address_Set(xsta,ysta,xend-1,yend-1);//设置显示范围

	uint16_t buf[150];
	memset(buf,color,150);

    esp_err_t ret;
    spi_transaction_t t;    

	uint16_t width = (xend-xsta+1);
	uint16_t height = (yend-ysta+1);
	int len=width*height;
	int cnt=0;
	while(1)
	{
		memset(&t, 0, sizeof(t)); 
		t.length=2*8*50;                     //Command is 8 bits
		t.tx_buffer=&buf[cnt*10];               //The data is the cmd itself
		t.user=(void*)0;                //D/C needs to be set to 0

		ret=spi_device_transmit(lcd_spi, &t);  //Transmit!

		//cnt+=10;
		cnt%=20;

		len-=50;
		if(len<0)
			break;	
	}				  	    
 }



void LCD_Fill_Colors2(u16 xsta,u16 ysta,u16 xend,u16 yend,uint16_t color)
{          
	uint32_t x=0,y=0; 
	uint16_t width = (xend-xsta+1);
	uint16_t height = (yend-ysta+1);
	long len=width*height;	
	SPI_DEBUG("清屏开始\r\n");

	LCD_Address_Set(xsta,ysta,xend,yend);//设置显示范围

#if 1

    for(y = 0; y <width*height; y+=1) 
	{


		//LCD_WR_data_2byte(color);
		LCD_WR_dataaa(color>>8,0);
		LCD_WR_dataaa(color,0);
		//LCD_WR_DATA(color);
    }





#endif

	uint16_t vol=0,vol1=0;
	uint8_t dat=0;
	vol=0x0080;

	dat = color>>8;
	//SPI_DEBUG("1:0x%x\r\n",vol);
	//dat=0xf3;
	vol|=(dat>>1);
	//SPI_DEBUG("2:0x%x\r\n",vol);
	vol|=((dat&0x01)<<15);

	dat = color&0xff;
	//SPI_DEBUG("1:0x%x\r\n",vol);
	//dat=0xf3;
	vol1|=(dat>>1);
	//SPI_DEBUG("2:0x%x\r\n",vol);
	vol1|=((dat&0x01)<<15);


    for(y = 0; y <width*height; y++) 
	{

        SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(LCD_SPI_NUM), SPI_USR_MOSI_DBITLEN, 9, SPI_USR_MOSI_DBITLEN_S);
        WRITE_PERI_REG((SPI_W0_REG(LCD_SPI_NUM)), vol);
        SET_PERI_REG_MASK(SPI_CMD_REG(LCD_SPI_NUM), SPI_USR);
        while (READ_PERI_REG(SPI_CMD_REG(LCD_SPI_NUM)) & SPI_USR);

        SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(LCD_SPI_NUM), SPI_USR_MOSI_DBITLEN, 9, SPI_USR_MOSI_DBITLEN_S);
        WRITE_PERI_REG((SPI_W0_REG(LCD_SPI_NUM)), vol1);
        SET_PERI_REG_MASK(SPI_CMD_REG(LCD_SPI_NUM), SPI_USR);
        while (READ_PERI_REG(SPI_CMD_REG(LCD_SPI_NUM)) & SPI_USR);

    }	

	SPI_DEBUG("清屏结束\r\n");
}

void LCD_Fill_Colors(u16 xsta,u16 ysta,u16 xend,u16 yend,lv_color_t* color_p)
{          
	uint32_t x=0,y=0; 
 
	uint16_t width = (xend-xsta+1);
	uint16_t height = (yend-ysta+1);
	long len=width*height;
    //xSemaphoreTakeRecursive(_spi_mux, portMAX_DELAY);

 #if 0   
	// LCD_Address_Set(xsta,ysta,xend,yend);//设置显示范围

    // for(y = 0; y <width*height; y++) 
	// {
	// 	LCD_WR_DATA(color_p->full);
	// 	color_p++;
    // }


    // for(y = ysta; y <= yend; y++) {
    //     for(x = xsta; x <= xend; x++) {

	// 	   LCD_DrawPoint(x, y,  (color_p->full));

    //     	color_p++;
    //     }
    // }
#else
	
#define lcd_spi_dat_len 50
    esp_err_t ret;
    spi_transaction_t t;   
	int cnt=0,i=0;
	int tx_mode=0;
	int tx_len = lcd_spi_dat_len;
	int break_cnt=0;
	uint16_t buf[lcd_spi_dat_len];
	memset(buf,RED,lcd_spi_dat_len);

	LCD_Address_Set(xsta,ysta,xend,yend);//设置显示范围	

	if(len<lcd_spi_dat_len)
	{
		tx_len = len;
		tx_mode=1;
	}

	while(1)
	{		 
		for(i=0;i<tx_len;i++)
		{
			buf[i]=SWAPBYTES(color_p[cnt*tx_len+i].full);
		}
		memset(&t, 0, sizeof(t));
		t.length=2*8*tx_len;    
		t.tx_buffer=&buf[0];               
		t.user=(void*)0;                
		ret=spi_device_transmit(lcd_spi, &t); 

		if(tx_mode==1)
			break;	
			
		cnt++;

		if(len>lcd_spi_dat_len)
		{
			len-=tx_len;
		}else
		{
			tx_len=len;
			len-=tx_len;
			if(++break_cnt>1)
				break;
		}
	}
#endif	

	//xSemaphoreGiveRecursive(_spi_mux);			  	    
 }



